module etc.dleveldb.iterator;

import deimos.leveldb.c;
import etc.dleveldb.slice;



import std.conv;

class Iterator
{

    @property:
    bool isValid() const
    {
        return cast(bool) leveldb_iter_valid(this._iterator);
    }
    
    bool empty() const
    {
        return !this.isValid;
    }

    void seekToFirst() => leveldb_iter_seek_to_first(this._iterator);
    void seekToLast() => leveldb_iter_seek_to_last(this._iterator);
    void seekTo(in string key) => leveldb_iter_seek(this._iterator, key._lib_obj_ptr__, key._lib_obj_size__);
    void next() => leveldb_iter_next(this._iterator);
    void prev() => leveldb_iter_prev(this._iterator);
  
    Slice key()
    in(isValid, "Iterator is not valid")
    {
        size_t valsize;
        void* val = cast(void*)leveldb_iter_key(this._iterator,&valsize);
        scope(failure) if(val) leveldb_free(val);
        return Slice(val,valsize,false);
    }

    Slice value()
    in(isValid, "Iterator is not valid")
    {
        size_t valsize;
        auto val = cast(void*)leveldb_iter_value(this._iterator,&valsize);
        scope(failure) if(val) leveldb_free(val);
        return Slice(val,valsize,false);
    }

    auto front()
    {
        return [this.key,this.value];
    }

    string status() inout
    {
        char* errptr = null;
        scope(exit) if(errptr) leveldb_free(errptr);
        leveldb_iter_get_error(this._iterator,&errptr);
        return to!string(errptr);
    }

    // 
    int opApply(int delegate(ref Slice) dg)
    {
        int ret = 0;
        for(seekToFirst;isValid;next)
        {
            auto v = this.value;
            ret = dg(v);
            if(ret) break;
        }
        return ret;
    }

    int opApplyReverse(int delegate(ref Slice) dg)
    {
        int ret = 0;
        for(seekToLast;isValid;prev)
        {
            auto v = this.value;
            ret = dg(v);
            if(ret) break;
        }
        return ret;
    }

    int opApply(int delegate(ref Slice, ref Slice) dg)
    {
        int ret = 0;
        for(seekToFirst;isValid;next)
        {
            auto k = this.key;
            auto v = this.value;
            ret = dg(k,v);
            if(ret) break;
        }
        return ret;
    }

    int opApplyReverse(int delegate(ref Slice, ref Slice) dg)
    {
        int ret = 0;
        for(seekToLast;isValid;prev)
        {
            auto k = this.key;
            auto v = this.value;
            ret = dg(k,v);
            if(ret) break;
        }
        return ret;
    }



    package:
    @property
    inout(leveldb_iterator_t*) ptr() inout
    {
        return this._iterator;
    }

    protected:
    leveldb_iterator_t*  _iterator;
}